home *** CD-ROM | disk | FTP | other *** search
Wrap
/* Define DETAIL if you want detail listings to be kept, this can * double the pointer memory required and slow things down. If you NEVER * want to do DETAIL listings then undefine it. On fast machines it really * doesn't matter, but on my Amiga I can notice the difference. You need * about 1.5 times the size of you log file in memory. */ #define DETAIL /*** glog 3.0 ***/ /*** glog.c -- analysis tool for Unix gopherd logs ***/ /*** Version 3.0 *** by: Andy Wick - awick@csugrad.cs.vt.edu *** This version is an almost TOTAL rewrite of glog. It now reads all *** the information into memory before it does ANYTHING. It then goes *** through the arguments one at a time. So inorder to effect something *** you must change it before the report. ie. Argument order matters now. *** *** Version 2.2 *** by: Chuck Shotton - cshotton@oac.hsc.uth.tmc.edu *** *** Version 2.1 *** by: Michael Mealling - Georgia Institute of Technology *** Office of Information Technology *** michael.meallingl@oit.gatech.edu *** 12/29/92 *** *** Versions 1.0 *** by: Chuck Shotton - U of Texas Health Science Center - Houston, *** Office of Academic Computing *** cshotton@oac.hsc.uth.tmc.edu *** 6/17/92 ***/ #include <stdio.h> #include <string.h> #include <stdlib.h> #ifdef THINK_C #include <console.h> #endif #define GLOG_VERSION "Gopher Log Analyzer v.3.0" /* GENERAL STUFF */ typedef unsigned char byte; /* Error log link list */ typedef struct enode_list { char *data; struct enode_list *next; } ELIST_REC, *ELIST_PTR; /* GOPHER LINE STUFF */ /* These are the different types of data that are currenly reconized*/ #define FILETYPE ' ' #define DIRTYPE 'D' #define MAILDIRTYPE 'M' #define FTPTYPE 'F' #define RANGETYPE 'R' /* One line of the gopher log is stored in here */ typedef struct gopher_line { byte day; byte month; short date; char *hostname; char *path; char type; } GOPHER_REC, *GOPHER_PTR; /* A Linked list of gopher lines */ typedef struct node_list { GOPHER_PTR data; short hits; struct node_list *next; } LIST_REC, *LIST_PTR; /* Main tree */ typedef struct node_rec { GOPHER_PTR data; #ifdef DETAIL LIST_REC *llist; #endif short hits; struct node_rec *left, *right; } NODE_REC, *NODE_PTR; /*** *** The cruft list is a general list for things that aren't parse-able by *** ProcessLine(). "cruft" kept for historical reasons. ***/ ELIST_PTR cruft = NULL; /*** *** The following lists are maintained. ***/ NODE_PTR hosts = NULL; NODE_PTR docs = NULL; NODE_PTR days = NULL; NODE_PTR dates = NULL; NODE_PTR types = NULL; /*** *** The following macro is used to insert things into the above lists *** If you add a new sorting type, don't forget to add it here. ***/ #define ADDDATA(data) hosts = Insert(hosts, data, HostsCmp); \ docs = Insert(docs, data, DocsCmp); \ dates = Insert(dates, data, DatesCmp); \ types = Insert(types, data, TypesCmp); \ days = Insert(days, data, DaysCmp); /*** *** Self-Documenting vars, that save memory ***/ char *ROOTNAME = "Root Connections"; char *Days[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; char *Months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; /* The base file name for gnuplot reports */ char BASE[7] = "gopher"; char *base = BASE; /* Plot Output */ #define REPORTOUT 0 #define GNUOUT 1 #define HISTOUT 2 /* Type of plot to do */ char OutPlot=GNUOUT; /* Used to tell the Plot routines that you are starting and stoping */ #define PLOTSTART (GOPHER_PTR)0 #define PLOTDONE (GOPHER_PTR)1 /* Width of reports */ byte Width = 62; /* 80 - WIDTHSUB */ #define WIDTHSUB 18 /* The width of the standard print stuff */ /* Information */ /* Internal */ #define NOINFO 0 #define DETAILINFO 1 /* Error log requested, but not a valid SORT TYPE */ #define ERRORINFO 'E' /* SORT TYPES */ /* Changing these will change the options also */ #define DATAINFO 'D' #define HOSTINFO 'H' #define WEEKDAYINFO 'W' #define MONTHDATEINFO 'M' #define TYPEINFO 'T' /* The only forward decleration needed, since I wrote this the pascal way, the way all programs should be written. You don't need all the stupid forward declerations, or prototypes. */ void PrintInfo(NODE_PTR tree, void print(GOPHER_PTR), int cmp(GOPHER_PTR a, GOPHER_PTR b), byte DetailType); /*******************************/ /* Add item to error log */ ELIST_PTR InsertErrorLog(ELIST_PTR list, char *data) { ELIST_PTR temp, temp2; if (NULL == (temp = (ELIST_PTR)malloc(sizeof(ELIST_REC)))) { fprintf(stderr, "Not enough memory to add to ErrorLog\n"); exit(1); } if (NULL == (temp->data = (char *)malloc(sizeof(char) * (strlen(data) +1)))) { fprintf(stderr, "Not enough memory to add to ErrorLog\n"); exit(1); } strcpy(temp->data, data); temp->next = NULL; if (list == NULL) return (temp); for (temp2 = list; temp2->next != NULL ; temp2 = temp2->next); temp2->next = temp; return(list); } #ifdef DETAIL /*******************************/ LIST_PTR InsertDetail(LIST_PTR list, GOPHER_PTR data) { LIST_PTR temp; if (NULL == (temp = (LIST_PTR)malloc(sizeof(LIST_REC)))) { fprintf(stderr, "Not enough memory to add to DetailList\n"); exit(1); } temp->data = data; temp->next = list; temp->hits = 1; return(temp); } #endif /*******************************/ /* Insert tree_element into the appropriate symbol table. Increment the */ /* number of hits if that element is already present. */ /* Insert list_element into linked list contained in the node that */ /* tree_element was put in. */ NODE_PTR Insert(NODE_PTR tree, GOPHER_PTR data, int cmp(GOPHER_PTR a, GOPHER_PTR b)) { int i; if (tree == NULL) { if (NULL == (tree = (NODE_PTR) malloc(sizeof(NODE_REC)))) { fprintf(stderr, "No memory for InsertHost\n"); exit(1); } tree->data = data; tree->left = tree->right = NULL; #ifdef DETAIL tree->llist = InsertDetail(NULL, data); #endif tree->hits = 1; return(tree); } i=cmp(data, tree->data); if (i > 0) tree->right = Insert(tree->right, data, cmp); else if (i<0) tree->left = Insert(tree->left, data, cmp); else { tree->hits += 1; #ifdef DETAIL tree->llist = InsertDetail(tree->llist, data); #endif } return(tree); } /*******************************/ NODE_PTR Find(NODE_PTR tree, GOPHER_PTR data, int cmp(GOPHER_PTR a, GOPHER_PTR b)) { int i; if (tree == NULL) { return (NULL); } i=cmp(data, tree->data); if (i > 0) return(Find(tree->right, data, cmp)); if (i<0) return(Find(tree->left, data, cmp)); return(tree); } /*******************************/ /* Get a single field from temp, and return the new spot */ char *getf(char *temp, char *field) { while(*temp == ' ') temp++; *field = '\0'; if (*temp == '\n') return(temp); while ((*temp != ' ') && (*temp != '\0')) *field++ = *temp++; *field = '\0'; return(temp); } /*******************************/ int TypesCmp(GOPHER_PTR a, GOPHER_PTR b) { return(a->type - b->type); } /*******************************/ int HostsCmp(GOPHER_PTR a, GOPHER_PTR b) { return(strcmp(a->hostname, b->hostname)); } /*******************************/ int DocsCmp(GOPHER_PTR a, GOPHER_PTR b) { return(strcmp(a->path, b->path)); } /*******************************/ int DaysCmp(GOPHER_PTR a, GOPHER_PTR b) { return(a->day - b->day); } /*******************************/ int DatesCmp(GOPHER_PTR a, GOPHER_PTR b) { int i = a->month - b->month; if (i == 0) return(a->date - b->date); else return(i); } /*******************************/ byte MonthStr2Num(char *str) { static char lastmonth[4] = "Jan"; /* Who knows if saving the last month */ static int lastmonthnum = 1; /* really makes it faster */ int i; if (strcmp(lastmonth, str) == 0) return(lastmonthnum); for(i=0;i<12;i++) if (strcmp(Months[i], str) == 0) { strcpy(lastmonth, Months[i]); lastmonthnum = i+1; return(lastmonthnum); } return(13); } /*******************************/ byte DayStr2Num(char *str) { static char lastday[4] = "Sun"; /* Same here. Is there a better way? */ static int lastdaynum = 1; int i; if (strcmp(lastday, str) == 0) return(lastdaynum); for(i=0;i<7;i++) if (strcmp(Days[i], str) == 0) { strcpy(lastday, Days[i]); lastdaynum = i+1; return(lastdaynum); } return(8); } /*******************************/ /* Read a line from the log file, parse it up, and insert the */ /* info into the appropriate tables. */ void ProcessLine(char *line) { GOPHER_PTR data; short len; char *temp; /* Used to save line, incase it is needed for cruft */ char junk[1025]; char message1[128]; char message2[128]; if (NULL == (data = (GOPHER_PTR)malloc(sizeof(GOPHER_REC)))) { fprintf(stderr, "Not enough memory. Sorry\n"); exit(1); } temp = line; temp = getf(temp, junk); /* Day */ if (8 == (data->day = DayStr2Num(junk))) { /* Not a real day of week */ free(data); cruft = InsertErrorLog(cruft, line); return; } temp = getf(temp, junk); /* Month */ if (13 == (data->month = MonthStr2Num(junk))) { /* Not a real month */ free(data); cruft = InsertErrorLog(cruft, line); return; } temp = getf(temp, junk); /* Date */ data->date = atoi(junk); temp = getf(temp, junk); temp = getf(temp, junk); temp = getf(temp, junk); temp = getf(temp ,junk); /* hostname */ if (junk[0] == ':') { /* A colon in the hostfield */ free(data); cruft = InsertErrorLog(cruft, line); return; } if (NULL == (data->hostname = (char *)malloc(sizeof(char) * (strlen(junk)+1)))) { fprintf(stderr, "Not enough memory. Sorry\n"); exit(1); } strcpy(data->hostname, junk); temp = getf(temp, junk); /* : COLON */ if (junk[0] != ':') { /* Now we don't have a colon */ free(data->hostname); free(data); cruft = InsertErrorLog(cruft, line); return; } temp = getf(temp, message1); temp = getf(temp, message2); while((*temp == ' ') && (*temp != '\0')) temp++; data->path = (char *)malloc(sizeof(char)*(strlen(temp)+1)); strcpy(data->path, temp); data->path[strlen(temp)] = '\0'; if (0 != (len = strlen(data->path))) { if (data->path[len-1] == '\n') data->path[len-1] = '\0'; } /*** *** This one is for that annoying 0.0.0.* IP address then gets stuck *** in the log when someone is trying to access something you ain't got ***/ if (strncmp(data->hostname,"0.0.0", 5) == 0) { free(data->path); free(data->hostname); free(data); cruft = InsertErrorLog(cruft, line); return; } if (strcmp(message1, "Root") == 0) { data->type = DIRTYPE; free(data->path); data->path = ROOTNAME; ADDDATA(data); } else if ((strcmp(message1, "retrieved") == 0) && (strcmp(data->path, "/") == 0)) { data->type = DIRTYPE; free(data->path); data->path = ROOTNAME; ADDDATA(data); } else if (strncmp(message2, "ftp:", 4) == 0) { strcpy(junk, data->path); /* Incase there was a space in the path */ free(data->path); /* Then we have to save off path, since it contains it*/ data->path = (char *)malloc(sizeof(char)*(strlen(message2)+strlen(junk))); strcpy(data->path, message2+4); strcat(data->path, junk); data->type = FTPTYPE; ADDDATA(data); } else if (strcmp(message1, "retrieved") == 0) { if (data->path[0] == '\0') { /* We some how retrieved nothing */ free(data->path); free(data->hostname); free(data); cruft = InsertErrorLog(cruft, line); return; } if (strcmp(message2, "directory") == 0) data->type = DIRTYPE; else if (strcmp(message2, "maildir") == 0) data->type = MAILDIRTYPE; else if (strcmp(message2, "file") == 0) data->type = FILETYPE; else if (strcmp(message2, "range") == 0) data->type = RANGETYPE; else { free(data->path); free(data->hostname); free(data); cruft = InsertErrorLog(cruft, line); return; } ADDDATA(data); } else /* wasn't anything we know about, g+ maybe?*/ { free(data->path); free(data->hostname); free(data); cruft = InsertErrorLog(cruft, line); return; } return; } /*******************************/ void GatherInfo(void) { char line[1025]; while(!feof(stdin)) { fgets(line, 1024, stdin); if (feof(stdin)) break; ProcessLine(line); } } /*******************************/ /* These vars are only valid right after a call to TreeTo?List. I could have * done some fancy var passing, but why bother. :) */ LIST_PTR GByNum; int GByNumHits; int GByNumMin; /* These two will be used for histograms in the future */ int GByNumMax; /*******************************/ void InsertSByNum(GOPHER_PTR data, short hits) { LIST_PTR temp, temp2; if (NULL == (temp = (LIST_PTR)malloc(sizeof(LIST_REC)))) { fprintf(stderr, "Not enough memory in InsertByNum\n"); exit(1); } temp->data = data; temp->next = NULL; temp->hits = hits; /* Figure out some vars */ if (hits < GByNumMin) GByNumMin = hits; if (hits > GByNumMax) GByNumMax = hits; GByNumHits += temp->hits; if (GByNum == NULL) GByNum = temp; else if (GByNum->hits < hits) { temp->next = GByNum; GByNum = temp; } else { temp2 = GByNum; while (temp2->next != NULL) { if (temp2->next->hits < hits) { temp->next = temp2->next; temp2->next = temp; return; } temp2 = temp2->next; } temp2->next = temp; } } /*******************************/ void InsertUByNum(GOPHER_PTR data, short hits) { LIST_PTR temp; if (NULL == (temp = (LIST_PTR)malloc(sizeof(LIST_REC)))) { fprintf(stderr, "Not enough memory in InsertByNum\n"); exit(1); } temp->data = data; temp->next = NULL; temp->hits = hits; /* Figure out some vars */ if (hits < GByNumMin) GByNumMin = hits; if (hits > GByNumMax) GByNumMax = hits; GByNumHits += temp->hits; if (GByNum == NULL) GByNum = temp; else { temp->next = GByNum; GByNum = temp; } } /*******************************/ /* I did two different routines so it would be faster :). I know this * doesn't follow the logic of the rest of the program, but oh well. * Do Inorder so that they remain in order, if two have the same * num of hits */ void TreeToSList(NODE_PTR tree) { if (tree == NULL) return; TreeToSList(tree->left); InsertSByNum(tree->data, tree->hits); TreeToSList(tree->right); } /*******************************/ void TreeToUList(NODE_PTR tree) { /* I did two different routines so it would be faster :). I know this * doesn't follow the logic of the rest of the program, but oh well. * Do reverse inorder, so the insert just basicly sticks it at the * beginning. Someone should rewrite this, maybe later :) */ if (tree == NULL) return; TreeToUList(tree->right); InsertUByNum(tree->data, tree->hits); TreeToUList(tree->left); } /*******************************/ NODE_PTR ListToTree(LIST_PTR list, int cmp(GOPHER_PTR, GOPHER_PTR)) { NODE_PTR temptree = NULL; for(;list != NULL; list = list->next) temptree = Insert(temptree, list->data, cmp); return(temptree); } /*******************************/ void FreeList(LIST_PTR list) { LIST_PTR temp; while (list != NULL) { temp = list; list = list->next; free(temp); } } /*******************************/ void FreeTree(NODE_PTR tree) { if (tree == NULL) return; FreeTree(tree->left); FreeTree(tree->right); #ifdef DETAIL FreeList(tree->llist); #endif free(tree); return; } /*******************************/ /* Given a string and and len, left justify and fill with spaces */ void printl(char *str, int len) { while (len > 0) { if (*str == '\n') str++; if (*str == '\0') putc(' ', stdout); else putc(*str++, stdout); len--; } } /*******************************/ void PrintData(GOPHER_PTR data) { if (data == NULL) { printf("Data:\n"); } else { printf("%c ",data->type); printl(data->path, Width - 2); } } /*******************************/ void PrintType(GOPHER_PTR data) { char *temp; if (data == NULL) { printf("Types:\n"); } else { switch(data->type) { case FILETYPE: temp = "File"; break; case DIRTYPE: temp = "Directory"; break; case MAILDIRTYPE: temp = "Mail Directory"; break; case FTPTYPE: temp = "FTP"; break; case RANGETYPE: temp = "Range"; break; } printl(temp, Width); } } /*******************************/ void PrintHost(GOPHER_PTR data) { if (data == NULL) { printf("Hosts:\n"); } else { printl(data->hostname, Width); } } /*******************************/ void PrintDay(GOPHER_PTR data) { if (data == NULL) { printf("Days:\n"); } else { printl(Days[data->day-1], Width); } } /*******************************/ void PrintDate(GOPHER_PTR data) { if (data == NULL) { printf("Dates:\n"); } else { printf("%3s %3s %2d", Days[data->day-1], Months[data->month-1], data->date); printl("\0", Width - 10); } } /*******************************/ void PlotData(FILE *rfp, int num, GOPHER_PTR data) { if (data == PLOTSTART) { fprintf(stderr, "Plot of Data is not currently supported, since I am not quite sure what it is suppose to do. Mail me ideas: awick@csugrad.cs.vt.edu\n"); } } /*******************************/ void PlotType(FILE *rfp, int num, GOPHER_PTR data) { char *temp; if (data == PLOTSTART) { fprintf(rfp,"set xtics ("); } else if (data == PLOTDONE) { fprintf(rfp,"\"\" %d)\n", num); fprintf(rfp,"set data style linespoints\n"); fprintf(rfp,"set tics out\n"); fprintf(rfp,"set grid\n"); fprintf(rfp,"set title \"Gopher Usage\"\n"); fprintf(rfp,"plot \"%s.dat\"\n", base); } else { switch(data->type) { case FILETYPE: temp = "File"; break; case DIRTYPE: temp = "Directory"; break; case MAILDIRTYPE: temp = "Mail Directory"; break; case FTPTYPE: temp = "FTP"; break; case RANGETYPE: temp = "Range"; break; } fprintf(rfp,"\"%s\" %d,", temp, num); } } /*******************************/ void PlotHost(FILE *rfp, int num, GOPHER_PTR data) { if (data == PLOTSTART) { fprintf(stderr, "Plot of Hosts is not currently supported, since I am not quite sure what it is suppose to do. Mail me ideas: awick@csugrad.cs.vt.edu\n"); } } /*******************************/ void PlotDay(FILE *rfp, int num, GOPHER_PTR data) { if (data == PLOTSTART) { fprintf(rfp,"set xtics ("); } else if (data == PLOTDONE) { fprintf(rfp,"\"\" %d)\n", num); fprintf(rfp,"set data style linespoints\n"); fprintf(rfp,"set tics out\n"); fprintf(rfp,"set grid\n"); fprintf(rfp,"set title \"Gopher Usage\"\n"); fprintf(rfp,"plot \"%s.dat\"\n", base); } else { fprintf(rfp,"\"%s\" %d,",Days[data->day-1], num); } } /*******************************/ void PlotDate(FILE *rfp, int num, GOPHER_PTR data) { if (data == PLOTSTART) { fprintf(rfp,"set xtics ("); } else if (data == PLOTDONE) { fprintf(rfp,"\"\" %d)\n", num); fprintf(rfp,"set data style linespoints\n"); fprintf(rfp,"set tics out\n"); fprintf(rfp,"set grid\n"); fprintf(rfp,"set title \"Gopher Usage\"\n"); fprintf(rfp,"plot \"%s.dat\"\n", base); } else { if ((data->date == 1) || (data->date == 15) || (num == 1)) fprintf(rfp,"\"%s/%d\" %d,",Months[data->month-1], data->date, num); } } #ifdef DETAIL /*******************************/ void DoDetail(NODE_PTR tree, byte DetailType) { NODE_PTR newtree; switch(DetailType) { case DATAINFO: newtree = ListToTree(tree->llist, DocsCmp); PrintInfo(newtree, PrintData, DocsCmp, DETAILINFO); break; case HOSTINFO: newtree = ListToTree(tree->llist, HostsCmp); PrintInfo(newtree, PrintHost, HostsCmp, DETAILINFO); break; case WEEKDAYINFO: newtree = ListToTree(tree->llist, DaysCmp); PrintInfo(newtree, PrintDay, DaysCmp, DETAILINFO); break; case MONTHDATEINFO: newtree = ListToTree(tree->llist, DatesCmp); PrintInfo(newtree, PrintDate, DatesCmp, DETAILINFO); break; case TYPEINFO: newtree = ListToTree(tree->llist, TypesCmp); PrintInfo(newtree, PrintType, TypesCmp, DETAILINFO); break; } FreeTree(newtree); } #endif /*******************************/ void PrintInfo(NODE_PTR tree, void print(GOPHER_PTR), int cmp(GOPHER_PTR a, GOPHER_PTR b), byte DetailType) { LIST_PTR temp; LIST_PTR ByNum; int ByNumHits; if (DetailType != DETAILINFO)/*We are printing Detail info now,so no headers*/ { print(NULL); printf("=========================================================\n"); } GByNum = NULL; /* Init the vars for the TreeToList function */ GByNumHits = 0; TreeToSList(tree); ByNum = GByNum; /* Save off and clear the globals vars, since this */ ByNumHits = GByNumHits; /* function can be called recurisively */ GByNum = NULL; temp = ByNum; while (temp != NULL) { #ifdef DETAIL if (DetailType == DETAILINFO) printf(" "); #endif print(temp->data); printf(" %4d (%2.2f%%)\n", temp->hits, (float)temp->hits*100.0/ByNumHits); #ifdef DETAIL if ((DetailType != NOINFO) && (DetailType != DETAILINFO)) DoDetail(Find(tree, temp->data, cmp), DetailType); /* Don't generate Detail for NOINFO or if we are already doing detail */ #endif temp = temp->next; } printf("\n"); FreeList(ByNum); } /*******************************/ void PlotInfo(NODE_PTR tree, void plot(FILE *, int, GOPHER_PTR)) { LIST_PTR temp; FILE *rfp, *dfp; char *fn; int points = 1; if (OutPlot == GNUOUT) { fn = (char *)malloc(strlen(base) + 5); sprintf(fn,"%s.run", base); if (NULL == (rfp = fopen(fn, "w"))) { fprintf(stderr, "Could not open file \"%s\" for plot run\n", fn); free(fn); return; } sprintf(fn,"%s.dat", base); if (NULL == (dfp = fopen(fn, "w"))) { fprintf(stderr, "Could not open file \"%s\" for plot data\n", fn); free(fn); return; } free(fn); } else { rfp = stdout; dfp = stdout; } plot(rfp, 0, PLOTSTART); GByNum = NULL; /* Init the vars for the TreeToList function */ GByNumHits = 0; GByNumMax = 0; GByNumMin = 36000; TreeToUList(tree); temp = GByNum; while (temp != NULL) { plot(rfp, points, temp->data); fprintf(dfp, "%d %d\n", points++, temp->hits); temp = temp->next; } plot(rfp, points, PLOTDONE); printf("\n"); FreeList(GByNum); } /*******************************/ void PrintErrorInfo() { ELIST_PTR temp = cruft; printf("=========================================================\n"); printf("Exception/Problem Report\n"); printf("NOTE: THESE ENTRIES MAY DENOTE A SERVER PROBLEM. THEY SHOULD BE LOOKED OVER!\n"); while (temp != NULL) { printf(temp->data); temp = temp->next; } printf("\n"); } /*******************************/ void PrintHelp() { #ifdef DETAIL fprintf(stderr,"Usage: glog [-%ch] [-<SORTTYPE>[<SORTTYPE>]] [-p<SORTTYPE>]\n", ERRORINFO); #else fprintf(stderr,"Usage: glog [-%ch] [-<SORTTYPE>] [-p<SORTTYPE>]\n", ERRORINFO); #endif fprintf(stderr, " [-w <width>] [-o <outputtype>] [-f <basefilename>]\n"); fprintf(stderr, " -%c = Error log -h = this help\n", ERRORINFO); fprintf(stderr, "\n"); fprintf(stderr, "SORTTYPE is one of the following\n"); fprintf(stderr, " %c = Host Names %c = Day of Week \n", HOSTINFO, WEEKDAYINFO); fprintf(stderr, " %c = Document Names %c = Month/Day\n", DATAINFO, MONTHDATEINFO); fprintf(stderr, " %c = Type\n", TYPEINFO); fprintf(stderr, "\n"); } /*******************************/ int main(argc, argv) int argc; char **argv; { int i = 1; #ifdef THINK_C argc = ccommand(&argv); #endif #ifdef DETAIL printf("%s with DETAIL\n", GLOG_VERSION); #else printf("%s\n", GLOG_VERSION); #endif fflush(stdout); if (1 == argc) { PrintHelp(); /* Clueless */ exit(-1); } GatherInfo(); fflush(stdout); fflush(stderr); while (i<argc) { switch (argv[i][1]) { case ERRORINFO: PrintErrorInfo(); break; case DATAINFO: PrintInfo(docs, PrintData, DocsCmp, argv[i][2]); break; case TYPEINFO: PrintInfo(types, PrintType, TypesCmp, argv[i][2]); break; case WEEKDAYINFO: PrintInfo(days, PrintDay, DaysCmp, argv[i][2]); break; case MONTHDATEINFO: PrintInfo(dates, PrintDate, DatesCmp, argv[i][2]); break; case HOSTINFO: PrintInfo(hosts, PrintHost, HostsCmp, argv[i][2]); break; case 'p': /*custom plots*/ switch (argv[i][2]) { case DATAINFO: PlotInfo(docs, PlotData); break; case TYPEINFO: PlotInfo(types, PlotType); break; case WEEKDAYINFO: PlotInfo(days, PlotDay); break; case MONTHDATEINFO: PlotInfo(dates, PlotDate); break; case HOSTINFO: PlotInfo(hosts, PlotHost); break; } break; case 'w': if (i<argc-1) Width = atoi(argv[++i]) - WIDTHSUB; break; case 'o': if (i<argc-1) OutPlot = atoi(argv[++i]); break; case 'f': if (i<argc-1) base = argv[++i]; break; case '?': case 'h': PrintHelp(); break; default: fprintf(stderr, "Unknown option \"%c\" . -h for help\n", argv[i][1]); break; } /*switch*/ i++; /*next arg...*/ } /*while*/ exit(0); } /*******************************/